﻿using FlickrNet;
using Model.Repository.Interfaces;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model.Classes;

namespace Model.Repository.Classes
{
    public class PhotoRepository : BaseRepository, IPhotoRepository
    {



        public SearchModel Search(SearchModel model)
        {
            model.PhotoCollections = MakeSearch(model);
            return model;
        }

        private List<Model.Classes.Photo> MakeSearch(SearchModel model)
        {
            List<Model.Classes.Photo> allPhotos = context.Photos.ToList();

            allPhotos.ForEach( p => p.Rank = 0);
            allPhotos.ForEach(p => p.Distance = 0);

            foreach (Model.Classes.Photo photo in allPhotos)
            {
                // porovnani podle jednoho tagu -> dalo by se rozsirit na vice tagu
                if (photo.Tags.Contains(" "+model.Tags+ " "))
                {
                    photo.Rank += 40000;
                }   
            }

            if (model.UseGeo == true)
            {
                allPhotos.ForEach(p => p.Distance = CalculateDistance(p.Longtitude, p.Latitude, model.Longtitude, model.Latitude));
                allPhotos = NormalizeDistance(allPhotos);
                allPhotos.ForEach(p => p.Rank += p.Distance * 30000);
            }

            
            if (model.UseDate == true)
            {
               allPhotos.ForEach(p =>
                   {
                    if (p.DateTaken.Value != null && p.DateTaken.Value >= model.MinDateTaken && p.DateTaken.Value <= model.MaxDateTaken)
                    {
                        p.Rank += 40000;
                    }
                   });
             
            }

            if (model.UseRotation == true)
            {
                allPhotos.ForEach(p =>
                {
                    if (p.Rotation.HasValue == true && p.Rotation.Value == model.Rotation)
                    {
                        p.Rank += 50000;
                    }
                });
            }

            if (model.UseDescription == true)
            {

                string[] descs = model.Description.ToLower().Split(":; .".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);


                allPhotos.ForEach(p =>
                    {
                        if (string.IsNullOrWhiteSpace(p.Descripton) == false)
                        {
                            string pom = p.Descripton.ToLower();
                            foreach (string desc in descs)
                            {
                                if (pom.Contains(desc))
                                {
                                    p.Rank += 40000;
                                }
                            }
                        }

                    });
                

            }
            

            return allPhotos.OrderByDescending(p => p.Rank).ToList();

            

        }

        private static double CalculateDistance(double lon1, double lat1, double lon2, double lat2)
        {
            const double R = 3956;
            const double degreesToRadians = Math.PI / 180;

            //convert from fractional degrees (GPS) to radians 
            lon1 *= degreesToRadians;
            lat1 *= degreesToRadians;
            lon2 *= degreesToRadians;
            lat2 *= degreesToRadians;

            double dlon = lon2 - lon1;
            double dlat = lat2 - lat1;
            double a = Math.Pow(Math.Sin(dlat / 2), 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Pow(Math.Sin(dlon / 2), 2);
            double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
            double d = R * c;

            return d;
        }

        private List<Model.Classes.Photo> NormalizeDistance(List<Model.Classes.Photo> list)
        {
            double max = list.Max(p => p.Distance);
            double min = list.Min(p => p.Distance);

            //normalized value(i) = (Value (i) - Min V)/(Max V - Min V) 

            list.ForEach(p => p.Distance = 1- ((p.Distance - min) / (max - min)));
            return list;
        }


        public PhotoInfo Get(string photoId)
        {
            return flickr.PhotosGetInfo(photoId);
        }




        public void LoadUniversum()
        {
            string[] tags = new string[] { "castle", "tree", "car", "boat", "city", "dog", "house", "woman", "ocean", "human", "animal","dog","tower","bridge" };

            for (int i = 0; i < tags.Length; i++)
            {


                PhotoSearchOptions opts = new PhotoSearchOptions();


                opts.BoundaryBox = BoundaryBox.Usa;
                opts.Tags = tags[i];
                opts.HasGeo = true;
                opts.Extras |= PhotoSearchExtras.Geo;
                opts.Extras |= PhotoSearchExtras.Tags;
                opts.Extras |= PhotoSearchExtras.DateTaken;
                opts.Extras |= PhotoSearchExtras.Description;
                opts.Extras |= PhotoSearchExtras.Rotation;
                
                




                
                StorePhotosToDatabase(flickr.PhotosSearch(opts));
            }

        }



        private void StorePhotosToDatabase(PhotoCollection collection)
        {
            foreach (FlickrNet.Photo src in collection)
            {
                Model.Classes.Photo dest = new Model.Classes.Photo();



                DateTime taken = new DateTime(src.DateTaken.Year, src.DateTaken.Month, src.DateTaken.Day);
                if (taken.Year > 1800)
                {
                    dest.DateTaken = taken;
                }
                else
                {
                    dest.DateTaken = null;
                }

                dest.Latitude = src.Latitude;
                dest.Longtitude = src.Longitude;
                



                dest.Tags = FlatTags(src.Tags);
                dest.FlickrPhotoId = src.PhotoId;

                dest.ThumbnailUrl = src.ThumbnailUrl;
                dest.ImageUrl = src.Medium640Url;

                dest.Descripton = src.Description;
                dest.Rotation = src.Rotation;

                SavePhoto(dest);

            }

            context.SaveChanges();


        }


        public void SavePhoto(Model.Classes.Photo photo)
        {
            context.Photos.Add(photo);
        }


        private string FlatTags(System.Collections.ObjectModel.Collection<string> collection)
        {
            StringBuilder builder = new StringBuilder();
            foreach (string tag in collection)
            {
                builder.Append(tag);
                builder.Append(" ");
            }

            return builder.ToString();
        }
    }
}
